<?php

namespace app\model\system;

use app\model\BaseModel;

/**
 * 系统日志模型
 * 对应数据表：oa_system_log
 */
class SystemLog extends BaseModel
{
    /**
     * 数据表名
     * @var string
     */
    protected $name = 'system_log';

    /**
     * 主键名
     * @var string
     */
    protected $pk = 'id';

    /**
     * 字段类型转换
     * @var array
     */
    protected $type = [
        'id' => 'integer',
        'admin_id' => 'integer',
        'user_name' => 'string',
        'log_type' => 'integer',
        'log_level' => 'integer',
        'module' => 'string',
        'controller' => 'string',
        'action' => 'string',
        'method' => 'string',
        'url' => 'string',
        'ip' => 'string',
        'user_agent' => 'string',
        'request_data' => 'string',
        'response_data' => 'string',
        'error_message' => 'string',
        'execution_time' => 'float',
        'create_time' => 'integer',
    ];

    /**
     * 可搜索字段
     * @var array
     */
    protected $searchField = ['user_name', 'module', 'controller', 'action', 'url', 'ip'];

    /**
     * 日志类型
     * @var array
     */
    public const LOG_TYPE = [
        1 => '登录日志',
        2 => '操作日志',
        3 => '错误日志',
        4 => '安全日志',
        5 => '系统日志',
    ];

    /**
     * 日志级别
     * @var array
     */
    public const LOG_LEVEL = [
        1 => 'DEBUG',
        2 => 'INFO',
        3 => 'WARNING',
        4 => 'ERROR',
        5 => 'CRITICAL',
    ];

    /**
     * 关联管理员
     * @return \think\model\relation\BelongsTo
     */
    public function admin()
    {
        return $this->belongsTo('app\model\admin\User', 'admin_id', 'id');
    }

    /**
     * 获取系统日志列表
     * @param array $params 查询参数
     * @return \think\Paginator
     */
    public function getLogList($params = [])
    {
        $where = [];
        
        if (!empty($params['admin_id'])) {
            $where[] = ['admin_id', '=', $params['admin_id']];
        }
        
        if (!empty($params['log_type'])) {
            $where[] = ['log_type', '=', $params['log_type']];
        }
        
        if (!empty($params['log_level'])) {
            $where[] = ['log_level', '=', $params['log_level']];
        }
        
        if (!empty($params['module'])) {
            $where[] = ['module', '=', $params['module']];
        }
        
        if (!empty($params['controller'])) {
            $where[] = ['controller', '=', $params['controller']];
        }
        
        if (!empty($params['action'])) {
            $where[] = ['action', '=', $params['action']];
        }
        
        if (!empty($params['method'])) {
            $where[] = ['method', '=', strtoupper($params['method'])];
        }
        
        if (!empty($params['ip'])) {
            $where[] = ['ip', '=', $params['ip']];
        }
        
        if (!empty($params['start_date'])) {
            $where[] = ['create_time', '>=', strtotime($params['start_date'])];
        }
        
        if (!empty($params['end_date'])) {
            $where[] = ['create_time', '<=', strtotime($params['end_date'] . ' 23:59:59')];
        }

        return $this->where($where)
            ->with(['admin'])
            ->order('id', 'desc')
            ->paginate([
                'list_rows' => $params['limit'] ?? 20,
                'page' => $params['page'] ?? 1,
            ]);
    }

    /**
     * 记录系统日志
     * @param array $data 日志数据
     * @return bool|int
     */
    public function recordLog($data)
    {
        $data['create_time'] = time();
        
        // 设置默认值
        $data['log_type'] = $data['log_type'] ?? 2; // 默认操作日志
        $data['log_level'] = $data['log_level'] ?? 2; // 默认INFO级别
        $data['method'] = isset($data['method']) ? strtoupper($data['method']) : 'GET';
        
        return $this->insertGetId($data);
    }

    /**
     * 记录登录日志
     * @param int $adminId 管理员ID
     * @param string $userName 用户名
     * @param string $ip IP地址
     * @param string $userAgent 用户代理
     * @param bool $success 是否成功
     * @param string $errorMessage 错误信息
     * @return bool|int
     */
    public function recordLoginLog($adminId, $userName, $ip, $userAgent, $success = true, $errorMessage = '')
    {
        return $this->recordLog([
            'admin_id' => $adminId,
            'user_name' => $userName,
            'log_type' => 1, // 登录日志
            'log_level' => $success ? 2 : 4, // INFO或ERROR
            'module' => 'admin',
            'controller' => 'login',
            'action' => $success ? 'login_success' : 'login_fail',
            'method' => 'POST',
            'url' => '/admin/login',
            'ip' => $ip,
            'user_agent' => $userAgent,
            'error_message' => $errorMessage,
        ]);
    }

    /**
     * 记录操作日志
     * @param int $adminId 管理员ID
     * @param string $userName 用户名
     * @param string $module 模块
     * @param string $controller 控制器
     * @param string $action 动作
     * @param string $method 请求方法
     * @param string $url 请求URL
     * @param string $ip IP地址
     * @param string $userAgent 用户代理
     * @param array $requestData 请求数据
     * @param array $responseData 响应数据
     * @param float $executionTime 执行时间
     * @return bool|int
     */
    public function recordOperationLog($adminId, $userName, $module, $controller, $action, $method, $url, $ip, $userAgent, $requestData = [], $responseData = [], $executionTime = 0)
    {
        return $this->recordLog([
            'admin_id' => $adminId,
            'user_name' => $userName,
            'log_type' => 2, // 操作日志
            'log_level' => 2, // INFO
            'module' => $module,
            'controller' => $controller,
            'action' => $action,
            'method' => $method,
            'url' => $url,
            'ip' => $ip,
            'user_agent' => $userAgent,
            'request_data' => json_encode($requestData, JSON_UNESCAPED_UNICODE),
            'response_data' => json_encode($responseData, JSON_UNESCAPED_UNICODE),
            'execution_time' => $executionTime,
        ]);
    }

    /**
     * 记录错误日志
     * @param int $adminId 管理员ID
     * @param string $userName 用户名
     * @param string $module 模块
     * @param string $controller 控制器
     * @param string $action 动作
     * @param string $method 请求方法
     * @param string $url 请求URL
     * @param string $ip IP地址
     * @param string $errorMessage 错误信息
     * @param array $requestData 请求数据
     * @return bool|int
     */
    public function recordErrorLog($adminId, $userName, $module, $controller, $action, $method, $url, $ip, $errorMessage, $requestData = [])
    {
        return $this->recordLog([
            'admin_id' => $adminId,
            'user_name' => $userName,
            'log_type' => 3, // 错误日志
            'log_level' => 4, // ERROR
            'module' => $module,
            'controller' => $controller,
            'action' => $action,
            'method' => $method,
            'url' => $url,
            'ip' => $ip,
            'error_message' => $errorMessage,
            'request_data' => json_encode($requestData, JSON_UNESCAPED_UNICODE),
        ]);
    }

    /**
     * 获取登录统计
     * @param string $startDate 开始日期
     * @param string $endDate 结束日期
     * @return array
     */
    public function getLoginStats($startDate = null, $endDate = null)
    {
        $where = [['log_type', '=', 1]]; // 登录日志
        
        if ($startDate) {
            $where[] = ['create_time', '>=', strtotime($startDate)];
        }
        
        if ($endDate) {
            $where[] = ['create_time', '<=', strtotime($endDate . ' 23:59:59')];
        }

        $stats = $this->where($where)
            ->field('DATE(FROM_UNIXTIME(create_time)) as date, COUNT(*) as count')
            ->group('date')
            ->order('date', 'asc')
            ->select()
            ->toArray();

        return $stats;
    }

    /**
     * 获取操作统计
     * @param string $startDate 开始日期
     * @param string $endDate 结束日期
     * @return array
     */
    public function getOperationStats($startDate = null, $endDate = null)
    {
        $where = [['log_type', '=', 2]]; // 操作日志
        
        if ($startDate) {
            $where[] = ['create_time', '>=', strtotime($startDate)];
        }
        
        if ($endDate) {
            $where[] = ['create_time', '<=', strtotime($endDate . ' 23:59:59')];
        }

        $moduleStats = $this->where($where)
            ->field('module, COUNT(*) as count')
            ->group('module')
            ->order('count', 'desc')
            ->select()
            ->toArray();

        $controllerStats = $this->where($where)
            ->field('controller, COUNT(*) as count')
            ->group('controller')
            ->order('count', 'desc')
            ->limit(10)
            ->select()
            ->toArray();

        return [
            'module_stats' => $moduleStats,
            'controller_stats' => $controllerStats,
            'total_operations' => $this->where($where)->count(),
        ];
    }

    /**
     * 获取错误统计
     * @param string $startDate 开始日期
     * @param string $endDate 结束日期
     * @return array
     */
    public function getErrorStats($startDate = null, $endDate = null)
    {
        $where = [['log_type', '=', 3]]; // 错误日志
        
        if ($startDate) {
            $where[] = ['create_time', '>=', strtotime($startDate)];
        }
        
        if ($endDate) {
            $where[] = ['create_time', '<=', strtotime($endDate . ' 23:59:59')];
        }

        $errorStats = $this->where($where)
            ->field('controller, action, COUNT(*) as count')
            ->group('controller, action')
            ->order('count', 'desc')
            ->limit(10)
            ->select()
            ->toArray();

        return [
            'error_stats' => $errorStats,
            'total_errors' => $this->where($where)->count(),
        ];
    }

    /**
     * 清理旧日志
     * @param int $days 保留天数
     * @return bool
     */
    public function cleanOldLogs($days = 90)
    {
        $expireTime = time() - ($days * 86400);
        
        return $this->where('create_time', '<', $expireTime)->delete();
    }

    /**
     * 删除日志
     * @param int|array $ids 日志ID
     * @return bool
     */
    public function deleteLog($ids)
    {
        if (is_array($ids)) {
            return $this->where('id', 'in', $ids)->delete();
        } else {
            return $this->where('id', $ids)->delete();
        }
    }

    /**
     * 搜索器：按管理员ID搜索
     * @param \think\db\Query $query
     * @param int $value
     */
    public function searchAdminIdAttr($query, $value)
    {
        $query->where('admin_id', $value);
    }

    /**
     * 搜索器：按日志类型搜索
     * @param \think\db\Query $query
     * @param int $value
     */
    public function searchLogTypeAttr($query, $value)
    {
        $query->where('log_type', $value);
    }

    /**
     * 搜索器：按日志级别搜索
     * @param \think\db\Query $query
     * @param int $value
     */
    public function searchLogLevelAttr($query, $value)
    {
        $query->where('log_level', $value);
    }

    /**
     * 搜索器：按模块搜索
     * @param \think\db\Query $query
     * @param string $value
     */
    public function searchModuleAttr($query, $value)
    {
        $query->where('module', $value);
    }

    /**
     * 搜索器：按控制器搜索
     * @param \think\db\Query $query
     * @param string $value
     */
    public function searchControllerAttr($query, $value)
    {
        $query->where('controller', $value);
    }

    /**
     * 搜索器：按动作搜索
     * @param \think\db\Query $query
     * @param string $value
     */
    public function searchActionAttr($query, $value)
    {
        $query->where('action', $value);
    }

    /**
     * 搜索器：按IP地址搜索
     * @param \think\db\Query $query
     * @param string $value
     */
    public function searchIpAttr($query, $value)
    {
        $query->where('ip', $value);
    }

    /**
     * 搜索器：按创建时间范围搜索
     * @param \think\db\Query $query
     * @param array $value
     */
    public function searchCreateTimeRangeAttr($query, $value)
    {
        if (is_array($value) && count($value) === 2) {
            $startTime = strtotime($value[0]);
            $endTime = strtotime($value[1] . ' 23:59:59');
            $query->whereBetween('create_time', [$startTime, $endTime]);
        }
    }
}